﻿/********************************************************************
	created:	2014/07/07
	created:	7:7:2014   16:14
	filename: 	C:\Users\MacGyver\Documents\Atmel Studio\6.2\HalloweenController\HalloweenController\BoardInit\Ports.cpp
	file path:	C:\Users\MacGyver\Documents\Atmel Studio\6.2\HalloweenController\HalloweenController\BoardInit
	file base:	Ports
	file ext:	cpp
	author:		MacGyver
	
	purpose:	Port class
*********************************************************************/

#ifdef __cplusplus
extern "C"
{
	#endif	
	#include <stddef.h>
	#include <inttypes.h>
	#include <stdint-gcc.h>
	#include <avr/interrupt.h>
	#ifdef __cplusplus
}
#endif
#include "BInit_328P.hpp"
#include "Ports.hpp"
#include "CDef.hpp"

PORT::PORT(volatile uint8_t * port)
{
	//Set the port addresses for the DDR and PORT values
	PORTx = port;
	DDRx = port - 1;
	PINx = port - 2;
	
	for(uint8_t u8PIN = 0; u8PIN < u8NoOfPINs; u8PIN++)
	{
		PINs[u8PIN] = new PIN(this, u8PIN);
	}
}

PORT::~PORT()
{
	//Set the port addresses for the DDR and PORT values
	PORTx = nullptr;
	DDRx = nullptr;
	PINx = nullptr;
}

void PIN::vClear()
{
	*PORTx->PINx &= ~(1<<u8Bit);
}

void PIN::vSet()
{
	*PORTx->PINx |= (1<<u8Bit);
}

void PIN::vSetDirection(tenDIRECTION dir)
{
	*PORTx->DDRx = (dir == this->OUTPUT ? (*PORTx->DDRx | (1<<u8Bit)) : (*PORTx->DDRx & ~(1<<u8Bit)));
}

void PIN::vSetPullUp(tenSTATE state)
{
	*PORTx->PORTx = (state == this->ON ? (*PORTx->PORTx | (1<<u8Bit)) : (*PORTx->PORTx & ~(1<<u8Bit)));
}

PIN::PIN(PORT * oPort, uint8_t pin)
{
	u8Bit = pin;
	PORTx = oPort;
}

PIN::tenSTATE PIN::enGet()
{
	return (tenSTATE)((*PORTx->PINx & (1<<u8Bit)) >> u8Bit);
}

static uint8_t u8Counter;
ISR(TIMER0_COMPA_vect)
{
	u8Counter = TCNT0;
}

PWM::PWM(PIN * pin, tenMODE mode)
{
	PINx = pin;
	TCCRxA = PINx->PORTx->PORTx + 0x19;
	TCCRxB = PINx->PORTx->PORTx + 0x1A;
	TCNTx = PINx->PORTx->PORTx + 0x1B;
	OCRx = PINx->PORTx->PORTx + 0x1C;
			
	switch(mode)
	{
		case MODE_FAST_PWM:
			PINx->vSetDirection(PIN::OUTPUT);

			vSetDuty(50);
			
			vSetInversion(INV_NON_INVERTED);

			vSetMode(mode);

			vSetPreScaler(PSCL_STOP);
			
			//Enable the ISR
			TIMSK0 |= 0b00000010;
			break;
			
		default:
			break;
	}
}

void PWM::vSetInversion(tenINVERSION inverted)
{
	*TCCRxA = SET_BYTE_VIA_MASK(*TCCRxA, (uint8_t)inverted, (uint8_t)INV_MASK);
}

void PWM::vSetPreScaler(tenPRESCALER prescale)
{
	*TCCRxB = SET_BYTE_VIA_MASK(*TCCRxB, (uint8_t)prescale, (uint8_t)PSCL_MASK);
}

void PWM::vSetMode(tenMODE mode)
{
	*TCCRxA = SET_BYTE_VIA_MASK(*TCCRxA, (uint8_t)mode, (uint8_t)MODE_MASK);
}

void PWM::vSetDuty(uint8_t duty)
{
	*OCRx = duty;
}
